﻿namespace STLTypeVisualizer
{
	using System;
	using System.Collections.Generic;
	using System.Runtime.InteropServices;
	using VisualGDBExpressions;

	internal abstract class ListFilter : TypeListBasedExpressionFilter
	{
		protected ListFilter(params string[] supportedTypes) : base(supportedTypes)
		{
		}

		protected abstract string EvalNode(string fullNameForEvaluator, IExpressionEvaluator evaluator);
		protected abstract string EvalSize(string fullNameForEvaluator, IExpressionEvaluator evaluator);
		protected abstract ListChildProvider CreateChildProvider(IExpressionEvaluator evaluator,
			string listType, ulong initialNodeAddr, IExpression actualMembersNode);

		protected override IExpression DoAttach(IExpression expr, IExpressionEvaluator evaluator)
		{
			string fullNameForEvaluator = expr.FullNameForEvaluator;
			char[] trimChars = new char[] { '&' };
			string listType = expr.Type.TrimEnd(trimChars);
			ExpressionValue value2 = evaluator.EvaluateExpression(EvalNode(fullNameForEvaluator, evaluator), "void *");
			if (!(value2 is ExpressionValue.Integral))
			{
				return null;
			}
			StaticExpressionFilter filter1 = new StaticExpressionFilter(expr);
			ExpressionValue valueLen = evaluator.EvaluateExpression(EvalSize(fullNameForEvaluator, evaluator), null);
			if (valueLen is ExpressionValue.Integral)
			{
				ulong Len = (valueLen as ExpressionValue.Integral).Value;
				filter1.ValueOverride = new ExpressionValue.Custom($"[{Len}个元素]");
			}
			else
				filter1.ValueOverride = new ExpressionValue.Custom("[展开以填充std::list]");
			VirtualExpressionNode actualMembersNode = new VirtualExpressionNode("[实际成员]", "", expr.Children);
			actualMembersNode.FixedValue = new ExpressionValue.Composite("{...}");
			filter1.ChildrenOverride = CreateChildProvider(evaluator, listType, (value2 as ExpressionValue.Integral).Value, actualMembersNode);
			return filter1;
		}

		protected abstract class ListChildProvider : IExpressionChildProvider
		{
			protected IExpressionEvaluator _Evaluator;
			protected string _ListType;
			protected ulong _InitialNodeAddr;
			protected IExpression _ActualMembersNode;
			protected bool _UseStorageSyntax;
			protected List<IExpression> _Children;

			public ListChildProvider(IExpressionEvaluator evaluator, string listType, ulong initialNodeAddr, IExpression actualMembersNode)
			{
				this._Evaluator = evaluator;
				this._ListType = listType;
				this._InitialNodeAddr = initialNodeAddr;
				this._ActualMembersNode = actualMembersNode;
			}

			private void LoadChildren()
			{
				if (this._Children == null)
				{
					List<IExpression> list1 = new List<IExpression>();
					list1.Add(this._ActualMembersNode);
					this._Children = list1;
					int num = 0;
					DateTime now = DateTime.Now;
					for (ListFilter.ListNode node = this.QueryNode(this._InitialNodeAddr, true); node != null; node = this.QueryNode(node.NextNodeAddr, false))
					{
						if (node.Value != null)
						{
							StaticExpressionFilter item = new StaticExpressionFilter(node.Value);
							item.ShortNameOverride = $"[{num}]";
							this._Children.Add(item);
							num++;
						}
						if (node.NextNodeAddr == this._InitialNodeAddr)
						{
							break;
						}
						if ((DateTime.Now - now).TotalSeconds > 10.0)
						{
							this._Children.Add(new VirtualExpressionNode("[遍历超时]", "", null));
							return;
						}
					}
				}
			}

			public ExpressionChildRange QueryChildren(int firstChild, int childCount)
			{
				ExpressionChildRange range1 = new ExpressionChildRange();
				range1.FirstChildIndex = 0;
				range1.Children = this._Children;
				return range1;
			}

			public int QueryChildrenCount(out ExpressionChildRange additionallyReturnedChildren)
			{
				this.LoadChildren();
				additionallyReturnedChildren = null;
				return ((this._Children == null) ? 0 : this._Children.Count);
			}

			protected abstract string EvalNext(ulong addr);
			protected abstract IExpression EvalValue(ulong addr);
			private ListFilter.ListNode QueryNode(ulong addr, bool skipValue)
			{
				ExpressionValue value2 = this._Evaluator.EvaluateExpression(EvalNext(addr), "void *");
				if (!(value2 is ExpressionValue.Integral))
				{
					return null;
				}
				ListFilter.ListNode node1 = new ListFilter.ListNode();
				node1.NextNodeAddr = (value2 as ExpressionValue.Integral).Value;
				ListFilter.ListNode node = node1;
				if (!skipValue)
				{
					node.Value = EvalValue(addr);
					if (node.Value == null)
					{
						return null;
					}
				}
				return node;
			}

			public bool ChildrenAvailable =>
				true;
		}

		private class ListNode
		{
			public ulong NextNodeAddr;
			public IExpression Value;
		}
	}

	internal class GccListFilter : ListFilter
	{
		static string[] textArray1 = new string[] { "std::list<" };
		public GccListFilter() : base(textArray1)
		{
		}

		protected override string EvalNode(string fullNameForEvaluator, IExpressionEvaluator evaluator)
		{
			return $"(void *)&(({fullNameForEvaluator})._M_impl._M_node)";
		}

		protected override string EvalSize(string fullNameForEvaluator, IExpressionEvaluator evaluator)
		{
			return $"((unsigned *)({fullNameForEvaluator})._M_impl._M_node._M_size)";
		}

		protected override ListChildProvider CreateChildProvider(IExpressionEvaluator evaluator, string listType, ulong initialNodeAddr, IExpression actualMembersNode)
		{
			return new GccListChildProvider(evaluator, listType, initialNodeAddr, actualMembersNode);
		}

		protected class GccListChildProvider : ListFilter.ListChildProvider
		{
			public GccListChildProvider(IExpressionEvaluator evaluator, string listType, ulong initialNodeAddr, IExpression actualMembersNode)
				: base(evaluator, listType, initialNodeAddr, actualMembersNode)
			{
			}

			protected override string EvalNext(ulong addr)
			{
				return $"(void *)(({this._ListType}::_Node *)0x{addr:x})->_M_next";
			}

			protected override IExpression EvalValue(ulong addr)
			{
				IExpression Value = null;
				if (!this._UseStorageSyntax)
				{
					Value = this._Evaluator.CreateExpression($"(({this._ListType}::_Node *)0x{addr:x})->_M_data", false);
				}
				if (Value == null)
				{
					string str = string.Format("*(({0}::value_type *)&((({0}::_Node *)0x{1:x})->_M_storage))", this._ListType, addr);
					Value = this._Evaluator.CreateExpression(str, false);
					if (Value != null)
					{
						this._UseStorageSyntax = true;
					}
				}

				return Value;
			}
		}
	}

	internal class ClangListFilter : ListFilter
	{
		static string[] textArray1 = new string[] { "std::__1::list<" };
		public ClangListFilter() : base(textArray1)
		{
		}

		protected override string EvalNode(string fullNameForEvaluator, IExpressionEvaluator evaluator)
		{
			return $"(void *)&(({fullNameForEvaluator}).__end_)";
		}

		protected override string EvalSize(string fullNameForEvaluator, IExpressionEvaluator evaluator)
		{
			return $"((unsigned *)({fullNameForEvaluator}).__size_alloc_)";
		}

		protected override ListFilter.ListChildProvider CreateChildProvider(IExpressionEvaluator evaluator, string listType, ulong initialNodeAddr, IExpression actualMembersNode)
		{
			return new ClangListChildProvider(evaluator, listType, initialNodeAddr, actualMembersNode);
		}

		private class ClangListChildProvider : ListChildProvider
		{
			public ClangListChildProvider(IExpressionEvaluator evaluator, string listType, ulong initialNodeAddr, IExpression actualMembersNode) :
				base(evaluator, listType, initialNodeAddr, actualMembersNode)
			{
			}

			protected override string EvalNext(ulong addr)
			{
				return $"(void *)(({this._ListType}::__node_base *)0x{addr:x})->__next_";
			}

			protected override IExpression EvalValue(ulong addr)
			{
				return this._Evaluator.CreateExpression($"(({this._ListType}::__node_base *)0x{addr:x})->__as_node()->__value_", false);
			}
		}
	}
}

